/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package org.jacusoft.annotation.util;

import java.util.HashMap;
import java.util.Map;

/**
 *
 * @author bc548
 */
public class AnnotationUtil {

  private static final Map<Object, Map> contextMap = new HashMap<Object, Map>();
  private static final Map<String, Object> globalContextMap = new HashMap<String, Object>();

  private AnnotationUtil() {
    super();
  }

  public static void push(String key, Object value) throws DuplicatedKeyException {
    if (key == null) {
      throw new NullPointerException("A key must be specified.");
    }
    if (value == null) {
      throw new NullPointerException("A value must be specified.");
    }
    if(existKey(key)){
      throw new DuplicatedKeyException("The specified key already exists.");
    }
    //
    globalContextMap.put(key, value);
  }

  public static void push(Object context, String key, Object value) throws InexistingContextException,DuplicatedKeyException {
    if (context == null) {
      throw new NullPointerException("A context must be specified.");
    }
    if (key == null) {
      throw new NullPointerException("A key must be specified.");
    }
    if (value == null) {
      throw new NullPointerException("A value must be specified.");
    }
    //
    if (!existContext(context)) {
      createContext(context);
    }
    if(existKey(context,key)){
      throw new DuplicatedKeyException("The specified key already exists in the specified context.");
    }
    //
    getContext(context).put(key, value);
  }

  public static Object pull(String key) {
    if (key == null) {
      throw new NullPointerException("A key must be specified.");
    }
    //
    return globalContextMap.get(key);
  }

  public static Object pull(Object context, String key) throws InexistingContextException {
    if (context == null) {
      throw new NullPointerException("A context must be specified.");
    }
    if (key == null) {
      throw new NullPointerException("A key must be specified.");
    }
    if (!existContext(context)) {
      throw new InexistingContextException("The specified context does not exist.");
    }
    //
    return getContext(context).get(key);
  }

  public static void clearContext(Object context) throws InexistingContextException {
    if (context == null) {
      throw new NullPointerException("A context must be specified.");
    }
    if(!existContext(context)){
      throw new InexistingContextException("The specified context does not exist.");
    }
    //
    getContext(context).clear();
  }

  public static boolean destroyContext(Object context) {
    if (context == null) {
      throw new NullPointerException("A context must be specified.");
    }
    //
    if(existContext(context)){
      contextMap.remove(context);
      return true;
    }
    else{
      return false;
    }
  }

  public static boolean existContext(Object context) {
    if (context == null) {
      throw new NullPointerException("A context must be specified.");
    }
    //
    return contextMap.containsKey(context);
  }
  
  private static Map<String,Object> getContext(Object context){
    if (context == null) {
      throw new NullPointerException("A context must be specified.");
    }
    //
    return contextMap.get(context);
  }

  private static void createContext(Object context) throws DuplicatedContextException {
    if (context == null) {
      throw new NullPointerException("A context must be specified.");
    }
    if (existContext(context)) {
      throw new DuplicatedContextException("The specified context already exists.");
    }
    //
    Map<String, Object> newContext = new HashMap<String, Object>();
    contextMap.put(context, newContext);
  }
  
  private static boolean existKey(String key){
    if (key == null) {
      throw new NullPointerException("A key must be specified.");
    }
    //
    return globalContextMap.containsKey(key);
  }
  
  private static boolean existKey(Object context,String key) throws InexistingContextException{
    if (context == null) {
      throw new NullPointerException("A context must be specified.");
    }
    if (key == null) {
      throw new NullPointerException("A key must be specified.");
    }
    if(!existContext(context)){
      throw new InexistingContextException("The specified context does not exist.");
    }
    //
    return getContext(context).containsKey(context);
  }

  private static class DuplicatedContextException extends RuntimeException {

    public DuplicatedContextException() {
      super();
    }

    public DuplicatedContextException(String message) {
      super(message);
    }

    public DuplicatedContextException(String message, Throwable source) {
      super(message, source);
    }

  }

}
